/**
* @file         
* @brief		单链表，带头结点.
* @details	    基本功能演示.
* @author		conkty@126.com
* @date		    2023
* @version	    v0.1
* @par 更新记录:         
*	v0.1: 初建\n
*/

#include <stdlib.h>
#include <stdio.h>

typedef struct LNode {
    int data;
    struct LNode *next;
} Node, *LinkList;

void initialize2(LinkList* pL) {
    // 创建头结点，内容用来保存结点数（不包括头结点）
    printf("info: initializing the L (with head).\n");

    *pL = (Node *)malloc(sizeof(Node));
    (*pL)->data = 0;
    (*pL)->next = NULL;
}


LinkList initialize() {
    // 创建头结点，内容用来保存结点数（不包括头结点）
    printf("info: initializing the L (with head).\n");

    LinkList L = (Node *)malloc(sizeof(Node));
    L->data = 0;
    L->next = NULL;
}

// 新增结点在任意位置
int add(LinkList L, int value, int pos) {
    printf("info: adding %d to %d ...\n", value, pos);
    // 要判断pos的合法性或强制改为合法.
    if (pos < 0 ) {
        printf("warn: negtive pos, be forced to 0.\n");
        pos = 0;
    }

    Node *p = L; // 取表头
    int i = 0;
    // 移动到指定位置的前一结点
    while(NULL != p && i < (pos-1)) {
        printf("info: moved to %d ...\n", i);
        p = p->next; // 不断后移
        ++i;
    }

    // 为新元素分配结点
    Node* newp = (Node *)malloc(sizeof(Node));
    newp->data = value;
    // 修改前驱后继关系
    newp->next = p->next;
    p->next = newp;

    // 更新头结点中存储的链表长度值
    // 注意该长度值不包括头结点本身
    L->data += 1;

    return 0;
}

// 移除指定位置结点
int delete(LinkList L, int pos) {
    // 要求: pos是从0开始的整数
    printf("info: removing node at %d ...\n", pos);
    if (pos < 0 ) {
        printf("warn: invalid pos.\n");
        return -1;
    }
    if (pos >= L->data) {
        printf("error: pos greater than L lenth.\n");
        return -2;
    }
    
    Node *p = L; // 取表头，实际指向了头结点
    int i = 0;
    // 移动到指定位置的前一结点
    // 注意此处条件 i<pos，与simple有差异, 不是 i<pos-1了
    // 因为头结点的存在，故链表总长多了一个，故移动次数也需多一个.
    while(NULL != p->next && i < pos) {
        printf("info: moved to %d ...\n", i);
        p = p->next; // 不断后移
        ++i;
    }
    // 此时, p应指向指定结点的直接前驱

    // 待删除结点
    Node * q = p->next;
    // p后继改为指定结点的后继
    p->next = q->next;
    // 销毁指定结点
    printf("removing: %p\n", q);
    free(q);

    // 更新头结点中存储的链表长度值
    L->data -= 1;

    return 0;
}

// 遍历，打印每个元素
void traverse(LinkList L) {
    Node *p = L; // 取表头
    printf("info: L length is  %d.\n", L->data);
    while (NULL != p) {
        printf("addr: %p, cell: %d, next: %p\n", p, p->data, p->next);
        p = p->next; // 不断后移
    }
}

// 销毁链表，逐一释放结点
void destroy(LinkList L) {
    printf("info: destroying the L.\n");

    Node *p = L;
    while (NULL != p) {
        // 先记录后继结点地址
        Node * next_bak = p->next;
        // 销毁当前结点
        printf("destroying: %p\n", p);
        free(p);
        p = next_bak;
    }
}

int main()
{
    /*
    LinkList L = NULL;
    initialize(&L);
    */
    LinkList L = initialize();
    traverse(L);

    add(L, 31, 1);
    add(L, 32, 2);
    add(L, 40, 0);
    traverse(L);

    delete(L, 1);
    traverse(L);

    destroy(L);

    return 0;
}
